package com.alien.admin.modules.container.service.impl;

import com.alien.admin.modules.container.repository.K8sPodMetricStatusHistoryRepository;
import com.alien.admin.modules.container.repository.K8sPodMetricStatusRepository;

import com.alien.admin.modules.container.service.K8sDeploymentStatusService;
import com.alien.admin.modules.container.service.K8sProjectService;
import com.alien.admin.modules.container.service.dto.*;
import com.alien.admin.modules.deploy.domain.DpK8sInstance;
import com.alien.admin.modules.deploy.domain.DpServerConfig;
import com.alien.admin.modules.deploy.repository.DpK8sInstanceRepository;
import com.alien.admin.modules.deploy.service.DpServerConfigService;
import com.alien.admin.modules.deploy.service.DpServerService;
import com.alien.admin.modules.deploy.service.dto.DpServerDto;
import com.alien.admin.modules.basic.domain.Pod;
import com.alien.admin.modules.basic.domain.ReplicaSet;
import com.alien.admin.modules.basic.service.K8sService;
import com.alien.admin.utils.DateUtil;

import com.alien.admin.utils.DeployConstant;
import com.alien.admin.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class K8sProjectServiceImpl implements K8sProjectService {
    private final DpServerService dpServerService;
    private final K8sPodMetricStatusHistoryRepository k8sPodMetricStatusHistoryRepository;
    private final K8sPodMetricStatusRepository k8sPodMetricStatusRepository;
    private final K8sDeploymentStatusService k8sDeploymentStatusService;
    private final DpK8sInstanceRepository dpK8sInstanceRepository;
    private final K8sService k8sService;
    private final DpServerConfigService dpServerConfigService;

    @Override
    public List<K8sProjectPodStatusDto> queryK8sProjectPodStatusList(K8sProjectQueryCriteria criteria) {

        // 获取项目在该环境所在的集群配置
        DpServerConfig dpServerConfig = dpServerConfigService.findDpServerConfig(criteria);
        Integer k8sId = dpServerConfig.getK8sInstanceId();
        String namespace = dpServerConfig.getK8sNameSpace();

        DpServerDto dpServer = dpServerService.findById(criteria.getProjectId());
        String deploymentName = String.format("%s-deployment", dpServer.getName());

        // 历史记录
        List<Map<String, Object>> podDataList = k8sPodMetricStatusHistoryRepository.queryPodNameList(k8sId, namespace, deploymentName, criteria.getMinuteBegin(), criteria.getMinuteEnd());
        List<String> podNameHistoryList = podDataList.stream().map(item -> String.valueOf(item.get("pod_name"))).collect(Collectors.toList());

        // 当前状态
        podDataList = k8sPodMetricStatusRepository.queryPodNameList(k8sId, namespace, deploymentName);
        List<String> podNameList = podDataList.stream().map(item -> String.valueOf(item.get("pod_name"))).collect(Collectors.toList());

        List<K8sProjectPodStatusDto> k8sProjectPodStatusDtoList = getK8sProjectPodStatusDtoList(podNameHistoryList, podNameList);
        return k8sProjectPodStatusDtoList;
    }

    private List<K8sProjectChartDto.ChartElm> queryK8sCpuHistoryStatus(Integer k8sId, String namespace, String podName, Long minuteBegin, Long minuteEnd) {
        List<Map<String, Object>> data = k8sPodMetricStatusHistoryRepository.queryCpuHistoryStatus(k8sId, namespace, podName, minuteBegin, minuteEnd);

        // 转换成图表数据
        List<K8sProjectChartDto.ChartElm> chartElmList = data.stream().map(item -> {
            K8sProjectChartDto.ChartElm chartElm = new K8sProjectChartDto.ChartElm();
            Double cpu = Double.valueOf(String.valueOf(item.get("cpu")));
            Long minuteSeconds = Long.valueOf(String.valueOf(item.get("minute"))) / 1000;

            String dt = DateUtil.formatYmdHm(minuteSeconds);
            Long cpum = new Double(cpu * 1024).longValue();

            chartElm.setDt(dt);
            chartElm.setValue(cpum);
            return chartElm;
        }).collect(Collectors.toList());

        return chartElmList;
    }

    @Override
    public K8sProjectChartDto queryPodCpuHistoryChartInfo(K8sProjectQueryCriteria criteria) {
        // 获取项目在该环境所在的集群配置
        DpServerConfig dpServerConfig = dpServerConfigService.findDpServerConfig(criteria);
        Integer k8sId = dpServerConfig.getK8sInstanceId();
        String namespace = dpServerConfig.getK8sNameSpace();

        DpServerDto dpServer = dpServerService.findById(criteria.getProjectId());
        String deploymentName = String.format("%s-deployment", dpServer.getName());

        String podName = criteria.getPodName();
        Long minuteBegin = criteria.getMinuteBegin();
        Long minuteEnd = criteria.getMinuteEnd();

        // 获取历史数据
        List<K8sProjectChartDto.ChartElm> chartElmList = queryK8sCpuHistoryStatus(k8sId, namespace, podName, minuteBegin, minuteEnd);

        Map<String, List<K8sProjectChartDto.ChartElm>> chartInfo = new HashMap<>(2);
        chartInfo.put("Cpu Used", chartElmList);

        // 获取cpu和mem的配置信息
        K8sDeploymentStatusDto k8sDeploymentStatusDto = queryK8sDeploymentStatusDto(k8sId, namespace, deploymentName);
        Long limitCpu = toLongCpu(k8sDeploymentStatusDto.getLimitCpu());

        List<K8sProjectChartDto.ChartElm> limitCpuCharInfo = generateLimitChartInfo(chartElmList, limitCpu);
        chartInfo.put("Cpu Limit", limitCpuCharInfo);

        K8sProjectChartDto k8sProjectChartDto = K8sProjectChartDto.build(chartInfo, "m");
        return k8sProjectChartDto;
    }

    private List<K8sProjectChartDto.ChartElm> generateLimitChartInfo(List<K8sProjectChartDto.ChartElm> chartElmList, Long limitValue) {
        List<K8sProjectChartDto.ChartElm> limitChartInfo = new ArrayList<>(chartElmList.size());
        chartElmList.stream().forEach(chartElm -> {
            K8sProjectChartDto.ChartElm elm = new K8sProjectChartDto.ChartElm();
            elm.setValue(limitValue);
            elm.setDt(chartElm.getDt());
            limitChartInfo.add(elm);
        });
        return limitChartInfo;
    }

    private List<K8sProjectChartDto.ChartElm> queryK8sMemHistoryStatus(Integer k8sId, String namespace, String podName, Long minuteBegin, Long minuteEnd) {
        List<Map<String, Object>> data = k8sPodMetricStatusHistoryRepository.queryMemHistoryStatus(k8sId, namespace, podName, minuteBegin, minuteEnd);

        // 转换成图表数据
        List<K8sProjectChartDto.ChartElm> chartElmList = data.stream().map(item -> {
            K8sProjectChartDto.ChartElm chartElm = new K8sProjectChartDto.ChartElm();
            Long mem = Long.valueOf(String.valueOf(item.get("mem")));
            Long minuteSeconds = Long.valueOf(String.valueOf(item.get("minute"))) / 1000;

            String dt = DateUtil.formatYmdHm(minuteSeconds);
            // 转换成Mib单位
            Long memMib = new Double(mem / 1024 / 1024).longValue();

            chartElm.setDt(dt);
            chartElm.setValue(memMib);
            return chartElm;
        }).collect(Collectors.toList());

        return chartElmList;
    }

    @Override
    public K8sProjectChartDto queryPodMemHistoryChartInfo(K8sProjectQueryCriteria criteria) {
        // 获取项目在该环境所在的集群配置
        DpServerConfig dpServerConfig = dpServerConfigService.findDpServerConfig(criteria);
        Integer k8sId = dpServerConfig.getK8sInstanceId();
        String namespace = dpServerConfig.getK8sNameSpace();

        DpServerDto dpServer = dpServerService.findById(criteria.getProjectId());
        String deploymentName = String.format("%s-deployment", dpServer.getName());

        String podName = criteria.getPodName();
        Long minuteBegin = criteria.getMinuteBegin();
        Long minuteEnd = criteria.getMinuteEnd();

        // 获取历史数据
        List<K8sProjectChartDto.ChartElm> chartElmList = queryK8sMemHistoryStatus(k8sId, namespace, podName, minuteBegin, minuteEnd);

        // 获取cpu和mem的配置信息
        K8sDeploymentStatusDto k8sDeploymentStatusDto = queryK8sDeploymentStatusDto(k8sId, namespace, deploymentName);
        Long limitMem = toLongMem(k8sDeploymentStatusDto.getLimitMem());

        Map<String, List<K8sProjectChartDto.ChartElm>> chartInfo = new HashMap<>(2);
        chartInfo.put("Memory Used", chartElmList);
        List<K8sProjectChartDto.ChartElm> limitMemCharInfo = generateLimitChartInfo(chartElmList, limitMem);
        chartInfo.put("Memory Limit", limitMemCharInfo);

        K8sProjectChartDto k8sProjectChartDto = K8sProjectChartDto.build(chartInfo, "Mib");
        return k8sProjectChartDto;
    }

    @Override
    public ReplicaSet queryCurrentReplicaSet(K8sProjectQueryCriteria criteria) {
        List<ReplicaSet> replicaSetList = queryReplicaSetList(criteria);
        if(replicaSetList == null || replicaSetList.isEmpty()) {
            return null;
        }

        Optional<ReplicaSet> replicaSetOptional = replicaSetList.stream().filter(replicaSet -> replicaSet.getAvailableReplicas() > 0).findFirst();
        return replicaSetOptional.orElse(null);
    }

    @Override
    public List<ReplicaSet> queryReplicaSetList(K8sProjectQueryCriteria criteria) {
        // 如果服务未配置，返回空数组
        Integer runningStatus = k8sDeploymentStatusService.findProjectRunningStatus(criteria);
        if(runningStatus.equals(DeployConstant.RUNNING_STATUS_UNKNOW)) {
            return new ArrayList<>(0);
        }

        // 获取项目在该环境所在的集群配置
        DpServerConfig dpServerConfig = dpServerConfigService.findDpServerConfig(criteria);
        Integer k8sInstanceId = dpServerConfig.getK8sInstanceId();
        String namespace = dpServerConfig.getK8sNameSpace();

        DpServerDto dpServer = dpServerService.findById(criteria.getProjectId());
        String deploymentName = String.format("%s-deployment", dpServer.getName());

        DpK8sInstance k8sInstance = dpK8sInstanceRepository.findById(k8sInstanceId).orElseGet(DpK8sInstance::new);
        List<ReplicaSet> replicaSetList = k8sService.getReplicaSets(k8sInstance, namespace, deploymentName);
        return replicaSetList;
    }

    @Override
    public Boolean rollbackReplicaSet(K8sProjectQueryCriteria criteria) {
        // 如果服务未配置，返回空数组
        Integer runningStatus = k8sDeploymentStatusService.findProjectRunningStatus(criteria);
        if(runningStatus.equals(DeployConstant.RUNNING_STATUS_UNKNOW)) {
            return false;
        }

        // 获取项目在该环境所在的集群配置
        DpServerConfig dpServerConfig = dpServerConfigService.findDpServerConfig(criteria);
        Integer k8sInstanceId = dpServerConfig.getK8sInstanceId();
        String namespace = dpServerConfig.getK8sNameSpace();

        DpServerDto dpServer = dpServerService.findById(criteria.getProjectId());
        String deploymentName = String.format("%s-deployment", dpServer.getName());

        DpK8sInstance k8sInstance = dpK8sInstanceRepository.findById(k8sInstanceId).orElseGet(DpK8sInstance::new);
        k8sService.rollback(k8sInstance, namespace, deploymentName, criteria.getRollbackReplicaSetName());
        return true;
    }

    @Override
    public List<Pod> queryPodList(K8sProjectQueryCriteria criteria) {
        DpServerConfig dpServerConfig = dpServerConfigService.findDpServerConfig(criteria);
        Integer k8sInstanceId = dpServerConfig.getK8sInstanceId();
        String namespace = dpServerConfig.getK8sNameSpace();
        String replicaSetName = criteria.getReplicaSetName();

        DpK8sInstance k8sInstance = dpK8sInstanceRepository.findById(k8sInstanceId).orElseGet(DpK8sInstance::new);
        List<Pod> podList = k8sService.getPods(k8sInstance, namespace, replicaSetName);
        return podList;
    }

    @Override
    public String queryPodLog(K8sProjectQueryCriteria criteria) {
        DpServerConfig dpServerConfig = dpServerConfigService.findDpServerConfig(criteria);
        Integer k8sInstanceId = dpServerConfig.getK8sInstanceId();
        String namespace = dpServerConfig.getK8sNameSpace();
        String podName = criteria.getPodName();

        DpK8sInstance k8sInstance = dpK8sInstanceRepository.findById(k8sInstanceId).orElseGet(DpK8sInstance::new);
        return k8sService.getPodLog(k8sInstance, namespace, podName);
    }

    @Override
    public K8sProjectChartDto queryK8sMemHistoryChartInfo(K8sProjectQueryCriteria criteria) {

        Integer k8sId = criteria.getK8sId();
        String namespace = criteria.getNamespace();

        Long minuteBegin = criteria.getMinuteBegin();
        Long minuteEnd = criteria.getMinuteEnd();

        // 获取历史数据
        List<K8sProjectChartDto.ChartElm> chartElmList = queryK8sMemHistoryStatus(k8sId, namespace, DeployConstant.K8S_SUM_NAME, minuteBegin, minuteEnd);

        Map<String, List<K8sProjectChartDto.ChartElm>> chartInfo = new HashMap<>(2);
        chartInfo.put("Memory Used", chartElmList);

        K8sProjectChartDto k8sProjectChartDto = K8sProjectChartDto.build(chartInfo, "Mib");
        return k8sProjectChartDto;
    }

    @Override
    public K8sProjectChartDto queryK8sCpuHistoryChartInfo(K8sProjectQueryCriteria criteria) {
        Integer k8sId = criteria.getK8sId();
        String namespace = criteria.getNamespace();

        Long minuteBegin = criteria.getMinuteBegin();
        Long minuteEnd = criteria.getMinuteEnd();

        // 获取历史数据
        List<K8sProjectChartDto.ChartElm> chartElmList = queryK8sCpuHistoryStatus(k8sId, namespace, DeployConstant.K8S_SUM_NAME, minuteBegin, minuteEnd);

        Map<String, List<K8sProjectChartDto.ChartElm>> chartInfo = new HashMap<>(2);
        chartInfo.put("Cpu Used", chartElmList);

        K8sProjectChartDto k8sProjectChartDto = K8sProjectChartDto.build(chartInfo, "m");
        return k8sProjectChartDto;
    }

    Long toLongCpu(String cpuStr) {
        if(StringUtils.isBlank(cpuStr)) {
            return 0L;
        }

        int mIndex = cpuStr.indexOf("m");
        if(mIndex != -1) {
            String cpuNumStr = cpuStr.substring(0, mIndex);
            return Long.valueOf(cpuNumStr);
        }

        return Long.valueOf(cpuStr) * 1024;
    }

    Long toLongMem(String memStr) {
        if(StringUtils.isBlank(memStr)) {
            return 0L;
        }

        int mIndex = memStr.indexOf("Ti");
        if(mIndex != -1) {
            String memNumStr = memStr.substring(0, mIndex);
            return Long.valueOf(memNumStr) * 1024 * 1024;
        }

        mIndex = memStr.indexOf("Gi");
        if(mIndex != -1) {
            String memNumStr = memStr.substring(0, mIndex);
            return Long.valueOf(memNumStr) * 1024;
        }

        mIndex = memStr.indexOf("Mi");
        if(mIndex != -1) {
            String memNumStr = memStr.substring(0, mIndex);
            return Long.valueOf(memNumStr);
        }

        mIndex = memStr.indexOf("Ki");
        if(mIndex != -1) {
            String memNumStr = memStr.substring(0, mIndex);
            return Long.valueOf(memNumStr) / 1024;
        }

        return Long.valueOf(memStr);
    }

    K8sDeploymentStatusDto queryK8sDeploymentStatusDto(Integer k8sId, String namespace, String deploymentName) {
        K8sDeploymentStatusQueryCriteria k8sDeploymentStatusQueryCriteria = new K8sDeploymentStatusQueryCriteria();
        k8sDeploymentStatusQueryCriteria.setK8sId(k8sId);
        k8sDeploymentStatusQueryCriteria.setNamespace(namespace);
        k8sDeploymentStatusQueryCriteria.setDeploymentName(deploymentName);
        List<K8sDeploymentStatusDto> k8sDeploymentStatusDtoList = k8sDeploymentStatusService.queryAll(k8sDeploymentStatusQueryCriteria);

        if(k8sDeploymentStatusDtoList.isEmpty()) {
           return new K8sDeploymentStatusDto();
        }

        return k8sDeploymentStatusDtoList.get(0);
    }

    List<K8sProjectPodStatusDto> getK8sProjectPodStatusDtoList(List<String> podNameHistoryList, List<String> podNameList) {

        List<K8sProjectPodStatusDto> k8sProjectPodStatusDtoList = podNameHistoryList.stream().map(podName -> {
            boolean alive = podNameList.contains(podName);

            K8sProjectPodStatusDto k8sProjectPodStatusDto = new K8sProjectPodStatusDto();
            k8sProjectPodStatusDto.setAlive(alive);
            k8sProjectPodStatusDto.setPodName(podName);
            return k8sProjectPodStatusDto;
        }).collect(Collectors.toList());
        return k8sProjectPodStatusDtoList;
    }
}
